﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
using System.Security.Cryptography;
using System.Windows.Forms;
using System.Security.Principal;
using System.Security.AccessControl;
using System.DirectoryServices.AccountManagement;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;
using System.Security;

namespace RunAs
{
    internal class Program
    {
        
        static void Main(string[] args)
        {
            string CURRENTPROCESS = Process.GetCurrentProcess().MainModule.FileName;
            string processPath = "";
            string workingDirectory = "";
            string user = "";
            string password = "";
            WindowsIdentity identity;
            try
            {
                using (FileStream file = File.OpenRead(CURRENTPROCESS))
                {
                    byte[] buffer = new byte[1024];
                    int len = (int)file.Length;
                    file.Position = len - 4;
                    int i = file.Read(buffer, 0, 4);
                    int tag = BitConverter.ToInt32(buffer, 0);
                    if (tag != 10086)
                    {
                        MessageBox.Show("未初始化", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        Environment.Exit(0);
                    }

                    // read user password
                    file.Position = len - 8;
                    file.Read(buffer, 0, 4);
                    int encryptDataLen = BitConverter.ToInt32(buffer, 0);
                    byte[] encryptData = new byte[encryptDataLen];
                    file.Position = len - 8 - encryptDataLen;
                    file.Read(buffer, 0, encryptDataLen);
                    Array.Copy(buffer, encryptData, encryptDataLen);

                    // read appPath
                    file.Position = len - 8 - encryptDataLen - 4;
                    file.Read(buffer, 0, 4);
                    int appPathLen = BitConverter.ToInt32(buffer, 0);
                    file.Position = len - 8 - encryptDataLen - 4 - appPathLen;
                    file.Read(buffer, 0, appPathLen);
                    string appPath = Encoding.UTF8.GetString(buffer, 0, appPathLen);
                    var tempStrArr = appPath.Split(new char[] { '\n' });
                    processPath = tempStrArr[0];
                    workingDirectory = tempStrArr[1];

                    // 解析用户名和密码
                    byte[] encryptKey = Encoding.UTF8.GetBytes(MD5Encrypt32(appPath));
                    tempStrArr = Encoding.UTF8.GetString(AesDecrypt(encryptData, encryptKey)).Split(new char[] { '\n' });
                    user = tempStrArr[0];
                    password = tempStrArr[1];

                    // 验证用户名密码
                    identity = WindowNativeMethod.GetWindowIdentityByUserAndPaswd(user, password);
                    if (identity == null)
                    {
                        MessageBox.Show("用户名或密码错误", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        Environment.Exit(0);
                    }

                    if(identity.Name.Substring(identity.Name.IndexOf('\\') + 1) != Environment.UserName)
                    {
                        Process p = ProcessUserLogonHelper.CreateProcessWithUserToken(Process.GetCurrentProcess().MainModule.FileName, user, password);
                        p.StartInfo.WorkingDirectory = Environment.SystemDirectory;
                        p.Start();
                        Environment.Exit(0);

                    }

                    // 查看是否是嵌入的可执行文件
                    file.Position = len - 8 - encryptDataLen - 4 - appPathLen - 4;
                    file.Read(buffer, 0, 4);
                    tag = BitConverter.ToInt32(buffer, 0);
                    if (tag == 1008611)
                    {
                        file.Position = len - 8 - encryptDataLen - 4 - appPathLen - 8;
                        file.Read(buffer, 0, 4);
                        int appLen = BitConverter.ToInt32(buffer, 0);
                        file.Position = len - 8 - encryptDataLen - 4 - appPathLen - 8 - appLen;
                        string tempAppPath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}{Path.GetExtension(processPath)}");
                        using (var app = File.Create(tempAppPath))
                        {
                            int currentIndex = 0;
                            while (currentIndex < appLen)
                            {
                                if (appLen - currentIndex <= 1024)
                                {
                                    int readSize = file.Read(buffer, 0, appLen - currentIndex);
                                    app.Write(buffer, 0, readSize);
                                    currentIndex += readSize;
                                }
                                else
                                {
                                    int readSize = file.Read(buffer, 0, 1024);
                                    app.Write(buffer, 0, readSize);
                                    currentIndex += readSize;
                                }
                            }
                        }
                        processPath = tempAppPath;

                        //// 需要把文件的读取执行权限赋予user用户
                        //FileSecurity fileSecurity = File.GetAccessControl(processPath);
                        //fileSecurity.AddAccessRule(new FileSystemAccessRule(
                        //    identity.Owner,
                        //    FileSystemRights.ReadAndExecute,
                        //    AccessControlType.Allow));
                        //File.SetAccessControl(processPath, fileSecurity);
                    }
                }

                if (!File.Exists(processPath) || !Directory.Exists(workingDirectory))
                {
                    MessageBox.Show("找不到文件或工作目录", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(0);
                }

                if(!WindowNativeMethod.UserHasFileSystemRightsForPath(identity, workingDirectory, FileSystemRights.Read))
                {
                    MessageBox.Show($"{user} 没有工作目录的读取权限", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(0);
                }

                if(!WindowNativeMethod.UserHasFileSystemRightsForPath(identity, processPath, FileSystemRights.Read))
                {
                    MessageBox.Show($"{user} 没有目标文件的执行权限", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    Environment.Exit(0);
                }

                //Console.WriteLine($"{processPath}\n{workingDirectory}\n{user}\n{password}");
                var process = new Process();
                process.StartInfo.FileName = processPath;
                process.StartInfo.UseShellExecute = true;
                process.StartInfo.WorkingDirectory = workingDirectory;

                // 指定管理员权限运行程序，没有runas是默认权限运行
                process.StartInfo.Verb = "runas";
                process.Start();

            }
            catch (Exception ex)
            {
                MessageBox.Show($"{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Console.WriteLine(ex);
                Thread.Sleep(1000);
            }


        }

        public static string MD5Encrypt32(string str)
        {
            MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(str));
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));//转化为小写的16进制
            }
            return sBuilder.ToString();
        }

        public static byte[] AesDecrypt(byte[] data, byte[] Key)
        {
            try
            {
                byte[] result;
                using (Aes aesAlg = Aes.Create())
                {
                    aesAlg.Key = Key;
                    aesAlg.Mode = CipherMode.ECB;
                    aesAlg.Padding = PaddingMode.PKCS7;
                    using (ICryptoTransform decryptor = aesAlg.CreateDecryptor())
                    {
                        using (MemoryStream msDecrypt = new MemoryStream())
                        {
                            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Write))
                            {
                                csDecrypt.Write(data, 0, data.Length);
                            }
                            result = msDecrypt.ToArray();
                        }
                    }

                }
                return result;
            }
            catch
            {
                return null;
            }
        }

    }

    
}
